#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gpiod.h>
#include <alsa/asoundlib.h>

#define GPIO_LINE 9 // 定义GPIO线的编号，这里是PF9

//开始录音
snd_pcm_t* record_start(const char* name,
                        snd_pcm_format_t format,
                        unsigned int channel,
                        unsigned int rate,
                        snd_pcm_uframes_t* period)
{
    snd_pcm_t *capture; // PCM设备句柄
    snd_pcm_hw_params_t *params; // PCM硬件参数
    int err; // 用于存储错误码
    int dir;

    // 打开PCM设备用于录音（捕捉）
    if ((err = snd_pcm_open(&capture, name, SND_PCM_STREAM_CAPTURE, 0)) < 0) {
        fprintf(stderr, "Error opening PCM device %s: %s\n", name, snd_strerror(err));
        return NULL;
    }

    // 分配参数对象，并用默认值填充
    snd_pcm_hw_params_alloca(&params);
    snd_pcm_hw_params_any(capture, params);

    // 设置参数
    // 设置访问类型：交错模式
    if ((err = snd_pcm_hw_params_set_access(capture, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf(stderr, "Error setting access: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    // 设置数据格式：16位小端
    if ((err = snd_pcm_hw_params_set_format(capture, params, format)) < 0) {
        fprintf(stderr, "Error setting format: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    // 设置声道数：立体声
    if ((err = snd_pcm_hw_params_set_channels(capture, params, channel)) < 0) {
        fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    // 设置采样率
    if ((err = snd_pcm_hw_params_set_rate_near(capture, params, &rate, &dir)) < 0) {
        fprintf(stderr, "Error setting rate: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }
    printf("sample rate: %d Hz\n", rate);

    // 设置硬件参数
    if ((err = snd_pcm_hw_params(capture, params)) < 0) {
        fprintf(stderr, "Error setting HW params: %s\n", snd_strerror(err));
        snd_pcm_close(capture);
        return NULL;
    }

    // 获取周期大小
    snd_pcm_hw_params_get_period_size(params, period, &dir);

    return capture;
}

//停止录音
void record_stop(snd_pcm_t* capture)
{
    snd_pcm_drain(capture); // 排空PCM设备
    snd_pcm_close(capture); // 关闭PCM设备
}

int main(void) {
    struct gpiod_chip *chip;    // 指向GPIO芯片的指针
    struct gpiod_line *line;    // 指向GPIO线的指针
    int value, last_value;      // 当前值和上一次的值，用于检测按钮状态变化

    snd_pcm_t *capture = NULL;  // PCM设备句柄，用于音频录制
    snd_pcm_uframes_t period;   // 每个周期的帧数
    char *buffer;               // 缓冲区，用于存储录制的音频数据
    FILE *pcm_file;             // 输出PCM文件的指针
    int err;                    // 错误码

    // 打开GPIO芯片
    chip = gpiod_chip_open_by_label("GPIOF");
    if (!chip) {
        perror("打开GPIO芯片失败");
        return 1;
    }

    // 获取指定的GPIO线
    line = gpiod_chip_get_line(chip, GPIO_LINE);
    if (!line) {
        perror("获取GPIO线失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 将GPIO线设置为输入模式
    if (gpiod_line_request_input(line, "key1")) {
        perror("请求将GPIO线设置为输入模式失败");
        gpiod_chip_close(chip);
        return 1;
    }

    // 获取初始的GPIO线值
    last_value = gpiod_line_get_value(line);

    // 无限循环检测GPIO线值的变化
    while (1) {
        // 获取当前的GPIO线值
        value = gpiod_line_get_value(line);

        // 如果当前值与上一次的值不同，说明按键状态发生了变化
        if (value != last_value) {
            // 按钮按下时
            if (value == 0 && capture == NULL) {
                printf("key pressed\n");

                // 开始录音
                capture = record_start("hw:0,1", SND_PCM_FORMAT_S16_LE, 2, 44100, &period);
                if (!capture) {
                    perror("录音启动失败");
                    gpiod_chip_close(chip);
                    return 1;
                }

                // 分配缓冲区用于存储音频数据
                buffer = (char *)malloc(snd_pcm_frames_to_bytes(capture, period));
                if (!buffer) {
                    perror("分配缓冲区失败");
                    record_stop(capture);
                    gpiod_chip_close(chip);
                    return 1;
                }

                // 打开输出PCM文件
                pcm_file = fopen("output.pcm", "wb");
                if (!pcm_file) {
                    perror("打开输出文件失败");
                    free(buffer);         // 释放缓冲区
                    record_stop(capture); // 关闭PCM设备
                    gpiod_chip_close(chip);
                    return 1;
                }

                printf("Recording...\n"); // 输出录音开始提示
            }
            // 按钮释放时
            else if (value == 1 && capture != NULL) {
                printf("key released\n");

                // 停止录音
                free(buffer);         // 释放缓冲区
                fclose(pcm_file);     // 关闭输出文件
                record_stop(capture); // 停止音频采集
                capture = NULL;       // 重置capture指针

                printf("Recording stopped.\n"); // 输出录音停止提示
            }

            // 更新上一次的值为当前值
            last_value = value;
        }

        // 如果正在录音，继续读取音频数据
        if (capture != NULL) {
            snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period);
            if (frames < 0) {
                fprintf(stderr, "读取音频数据出错: %s\n", snd_strerror(frames));
                snd_pcm_recover(capture, frames, 0); // 尝试恢复PCM设备
            }
            // 将读取的数据写入输出文件
            fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, pcm_file);
        }

    }

    // 释放GPIO线资源
    gpiod_line_release(line);
    // 关闭GPIO芯片
    gpiod_chip_close(chip);

    return 0;
}